﻿// ===============================================================================
// StringHelper.cs
// EOS Framework
// ===============================================================================
// Copyright (c) EOS Development Group. All rights reserved.
// ===============================================================================

namespace EOS.Framework.Tools
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Text.RegularExpressions;

    /// <summary>
    /// Some Helper Methods for Strings.
    /// </summary>
    public static class StringHelper
    {
        /// <summary>
        /// Regular Expression to clean up a string.
        /// </summary>
        private static Regex cleanRegEx = new Regex(@"\s+|_|-|\.", RegexOptions.Compiled);

        /// <summary>
        /// Determines whether the specified string to check is empty or has only
        /// whitespaces.
        /// </summary>
        /// <param name="stringToCheck">The string to check.</param>
        /// <returns>
        /// 	<c>true</c> if the specified string to check is empty or has only
        /// whitespaces; otherwise, <c>false</c>.
        /// </returns>
        [SuppressMessage("Microsoft.Performance", "CA1820")]
        public static bool IsEmptyOrBlanksOnly(string stringToCheck)
        {
            bool isInvalid = false;

            if (string.IsNullOrEmpty(stringToCheck) || stringToCheck.Trim().Equals(string.Empty))
            {
                isInvalid = true;
            }

            return isInvalid;
        }

        #region Plural String Conversion

        /// <summary>
        /// Converts a word to its plural equivalent.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        private static string MakePlural(string word)
        {
            Regex plural1 = new Regex("(?<keep>[^aeiou])y$");
            Regex plural2 = new Regex("(?<keep>[aeiou]y)$");
            Regex plural3 = new Regex("(?<keep>[sxzh])$");
            Regex plural4 = new Regex("(?<keep>[^sxzhy])$");

            string result = word;

            if (plural1.IsMatch(word))
            {
                result = plural1.Replace(word, "${keep}ies");
            }
            else if (plural2.IsMatch(word))
            {
                result = plural2.Replace(word, "${keep}s");
            }
            else if (plural3.IsMatch(word))
            {
                result = plural3.Replace(word, "${keep}es");
            }
            else if (plural4.IsMatch(word))
            {
                result = plural4.Replace(word, "${keep}s");
            }

            return result;
        }

        /// <summary>
        /// Converts the specified word to plural word in pascal case. The
        /// word parts must be seperated by underscore.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        /// <exception cref="ArgumentNullException"><paramref word="word"/> is
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref word="word"/> is
        /// a string of length 0 or has only whitespaces.</exception>
        public static string MakePluralPascalCase(this string word)
        {
            if (word == null)
            {
                throw new ArgumentNullException("word");
            }

            if (IsEmptyOrBlanksOnly(word))
            {
                throw new ArgumentException(
                    "String parameter cannot be empty and cannot contain only blanks", "word");
            }

            string result = string.Empty;

            string[] wordParts = word.Split(new char[] { '_', '.', '-' });
            for (int i = 0; i < wordParts.Length; i++)
            {
                result += ToBeginUpper(wordParts[i]);
            }

            return MakePlural(result);
        }

        /// <summary>
        /// Converts the specified word to plural word in camel case. The
        /// word parts must be seperated by underscore.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        /// <exception cref="ArgumentNullException"><paramref word="word"/> is
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref word="word"/> is
        /// a string of length 0 or has only whitespaces.</exception>
        public static string MakePluralCamelCase(this string word)
        {
            if (word == null)
            {
                throw new ArgumentNullException("word");
            }

            if (IsEmptyOrBlanksOnly(word))
            {
                throw new ArgumentException(
                    "String parameter cannot be empty and cannot contain only blanks", "word");
            }

            string result = string.Empty;

            string[] wordParts = word.Split(new char[] { '_', '.', '-' });
            for (int i = 0; i < wordParts.Length; i++)
            {
                if (i == 0)
                {
                    result += ToBeginLower(wordParts[i]);
                }
                else
                {
                    result += ToBeginUpper(wordParts[i]);
                }
            }

            return MakePlural(result);
        }

        #endregion

        #region Singular String Conversion

        /// <summary>
        /// Converts a word to its singular equivalent.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        private static string MakeSingular(string word)
        {
            Regex plural1 = new Regex("(?<keep>[^aeiou])ies$");
            Regex plural2 = new Regex("(?<keep>[aeiou]y)s$");
            Regex plural3 = new Regex("(?<keep>[sxzh])es$");
            Regex plural4 = new Regex("(?<keep>[^sxzhyu])s$");

            string result = word;

            if (plural1.IsMatch(word))
            {
                result = plural1.Replace(word, "${keep}y");
            }
            else if (plural2.IsMatch(word))
            {
                result = plural2.Replace(word, "${keep}");
            }
            else if (plural3.IsMatch(word))
            {
                result = plural3.Replace(word, "${keep}");
            }
            else if (plural4.IsMatch(word))
            {
                result = plural4.Replace(word, "${keep}");
            }

            return result;
        }

        /// <summary>
        /// Converts the specified word to singular word in pascal case. The
        /// word parts must be seperated by underscore.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        /// <exception cref="ArgumentNullException"><paramref word="word"/> is
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref word="word"/> is
        /// a string of length 0 or has only whitespaces.</exception>
        public static string MakeSingularPascalCase(this string word)
        {
            if (word == null)
            {
                throw new ArgumentNullException("word");
            }

            if (IsEmptyOrBlanksOnly(word))
            {
                throw new ArgumentException(
                    "String parameter cannot be empty and cannot contain only blanks", "word");
            }

            string result = string.Empty;

            string[] wordParts = word.Split(new char[] { '_', '.', '-' });
            for (int i = 0; i < wordParts.Length; i++)
            {
                result += ToBeginUpper(wordParts[i]);
            }

            return MakeSingular(result);
        }

        /// <summary>
        /// Converts the specified word to singular word in camel case. The
        /// word parts must be seperated by underscore.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        /// <exception cref="ArgumentNullException"><paramref word="word"/> is
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref word="word"/> is
        /// a string of length 0 or has only whitespaces.</exception>
        public static string MakeSingularCamelCase(this string word)
        {
            if (word == null)
            {
                throw new ArgumentNullException("word");
            }

            if (IsEmptyOrBlanksOnly(word))
            {
                throw new ArgumentException(
                    "String parameter cannot be empty and cannot contain only blanks.", "word");
            }

            string result = string.Empty;

            string[] wordParts = word.Split(new char[] { '_', '.', '-' });
            for (int i = 0; i < wordParts.Length; i++)
            {
                if (i == 0)
                {
                    result += ToBeginLower(wordParts[i]);
                }
                else
                {
                    result += ToBeginUpper(wordParts[i]);
                }
            }

            return MakeSingular(result);
        }

        #endregion

        /// <summary>
        /// Makes a word begin lower. All characters will
        /// be small letters.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        /// <exception cref="ArgumentNullException"><paramref word="word"/> is
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref word="word"/> is
        /// a string of length 0 or has only whitespaces.</exception>
        public static string ToBeginLower(this string word)
        {
            if (word == null)
            {
                throw new ArgumentNullException("word");
            }

            if (IsEmptyOrBlanksOnly(word))
            {
                throw new ArgumentException(
                    "String parameter cannot be empty and cannot contain only blanks.", "word");
            }

            string output = cleanRegEx.Replace(word, "");
            return char.ToLower(output[0], CultureInfo.CurrentCulture) + output.Substring(1);
        }

        /// <summary>
        /// Makes a word begin upper. The first character will be 
        /// a capital letter, the following characters will be lower.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        /// <exception cref="ArgumentNullException"><paramref word="word"/> is
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref word="word"/> is
        /// a string of length 0 or has only whitespaces.</exception>
        public static string ToBeginUpper(this string word)
        {
            if (word == null)
            {
                throw new ArgumentNullException("word");
            }

            if (IsEmptyOrBlanksOnly(word))
            {
                throw new ArgumentException(
                    "String parameter cannot be empty and cannot contain only blanks.", "word");
            }

            string output = cleanRegEx.Replace(word, "");
            return char.ToUpper(output[0], CultureInfo.CurrentCulture) + output.Substring(1);
        }

        /// <summary>
        /// Converts the specified word pascal case. The
        /// word parts must be seperated by underscore.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        /// <exception cref="ArgumentNullException"><paramref word="word"/> is
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref word="word"/> is
        /// a string of length 0 or has only whitespaces.</exception>
        public static string ToPascalCase(this string word)
        {
            if (word == null)
            {
                throw new ArgumentNullException("word");
            }

            if (IsEmptyOrBlanksOnly(word))
            {
                throw new ArgumentException(
                    "String parameter cannot be empty and cannot contain only blanks.", "word");
            }

            string result = string.Empty;

            string[] wordParts = word.Split(new char[] { '_', '.', '-' });
            for (int i = 0; i < wordParts.Length; i++)
            {
                result += ToBeginUpper(wordParts[i]);
            }

            return result;
        }

        /// <summary>
        /// Converts the specified word in camel case. The
        /// word parts must be seperated by underscore.
        /// </summary>
        /// <param name="word">The word to convert.</param>
        /// <returns>The converted word.</returns>
        /// <exception cref="ArgumentNullException"><paramref word="word"/> is
        /// null (Nothing in Visual Basic).</exception>
        /// <exception cref="ArgumentException"><paramref word="word"/> is
        /// a string of length 0 or has only whitespaces.</exception>
        public static string ToCamelCase(this string word)
        {
            if (word == null)
            {
                throw new ArgumentNullException("word");
            }

            if (IsEmptyOrBlanksOnly(word))
            {
                throw new ArgumentException(
                    "String parameter cannot be empty and cannot contain only blanks.", "word");
            }

            string result = string.Empty;

            string[] wordParts = word.Split(new char[] { '_', '.', '-' });
            for (int i = 0; i < wordParts.Length; i++)
            {
                if (i == 0)
                {
                    result += ToBeginLower(wordParts[i]);
                }
                else
                {
                    result += ToBeginUpper(wordParts[i]);
                }
            }

            return result;
        }

        /// <summary>
        /// Cuts the specified string if the length is greater than the given maxLength
        /// and puts the prefix to the end.
        /// </summary>
        /// <param name="stringToTrim">The string to cut. Cannot be null (Nothing in Visual Basic).</param>
        /// <param name="maxLength">Length of the max.</param>
        /// <param name="prefix">The prefix.</param>
        /// <returns>The string to cut.</returns>
        /// <exception cref="ArgumentNullException"><param name="stringToCut"/> is null (Nothing in Visual Basic).</exception>
        public static string Cut(this string stringToCut, int maxLength, string prefix)
        {
            if (stringToCut == null)
            {
                throw new ArgumentNullException("stringToCut");
            }

            string result = stringToCut;
            if (stringToCut.Length > maxLength)
            {
                result = result.Substring(0, (int)maxLength);
                if (prefix != null)
                {
                    result += prefix;
                }
            }
            return result;
        }
    }
}
